package org.andes.kownledge.operator;

import java.util.List;

import org.andes.base.Bindings;
import org.andes.kownledge.operator.executable.AddToWm;
import org.andes.kownledge.operator.executable.AnyMember;
import org.andes.kownledge.operator.executable.Bind;
import org.andes.kownledge.operator.executable.Debug;
import org.andes.kownledge.operator.executable.InWm;
import org.andes.kownledge.operator.executable.Not;
import org.andes.kownledge.operator.executable.ReDebug;
import org.andes.kownledge.operator.executable.SetOf;
import org.andes.kownledge.operator.executable.Test;
import org.andes.kownledge.operator.executable.WmOrDerive;
import org.andes.kownledge.operator.func.Func;
import org.andes.sgg.st;
import org.armedbear.lisp.Cons;
import org.armedbear.lisp.LispObject;
import org.armedbear.lisp.Symbol;

public abstract class Executable extends Predication{
	protected String type;

	public Executable(){
		type=this.getClass().getSimpleName();
	}
	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	
	public static Not buildNot(LispObject lo){
		if(lo instanceof Cons){
			List<LispObject> parts=((Cons)lo).toList();
			Not not=new Not();
			for(int i=1;i<parts.size();i++){
				Term term= TermBuilder.buildTerm(parts.get(i));
				NoAtom func=(NoAtom)term;
				not.addFunc(func);
			}			
			return not;
		}
		return null;

		
	}

	public static Executable buildInwm(LispObject lo) {
		 InWm inwm=new InWm();
		 Term term=TermBuilder.buildTerm(lo.cadr());
		 inwm.setTerm(term);
		return inwm;
	}

	public static Executable buildWmOrDerive(LispObject lo) {
		WmOrDerive wod=new WmOrDerive();
		 Term term=TermBuilder.buildTerm(lo.cadr());
		 wod.setTerm(term);
		return wod;
	}

	public static Executable buildAddToWm(LispObject lo) {
		AddToWm wod=new AddToWm();
		 Term term=TermBuilder.buildTerm(lo.cadr());
		 wod.setTerm(term);
		return new AddToWm();
	}

	public static Executable buildTest(LispObject lo) {

		if(lo instanceof Cons){
			List<LispObject> parts=((Cons)lo).toList();
			Test test=new Test();
			for(int i=1;i<parts.size();i++){
				Term term= TermBuilder.buildTerm(parts.get(i));
				NoAtom func=(NoAtom)term;
				test.addFunc(func);
			}			
			return test;
		}
		return null;
		
	}

	public static Executable buildAnyMember(LispObject lo) {
		AnyMember am=new AnyMember();
		 
		List<LispObject> parts= lo.toList();
		Term term=TermBuilder.buildTerm(parts.get(1));
		if(parts.get(2) instanceof Cons){
			List<LispObject> rest=parts.get(2).toList();
			for(LispObject o:rest){
				am.addSetElem(TermBuilder.buildTerm(o));
			}
		}else{
			am.addSetElem(TermBuilder.buildTerm(parts.get(2)));
		}
		
		am.setTerm(term);
		return am;
	}

	public static Executable buildCount(LispObject lo) {
		return new Count();
	}

	
	// (setof (vector ?b (force ?b . ?rest) ?dir)
	//        (force ?b . ?rest) 
	//        ?forces)
	public static Executable buildSetof(LispObject lo) {
		if(lo instanceof Cons){
			List<LispObject> parts=((Cons)lo).toList();
			SetOf setof=new SetOf();
			Term goal= TermBuilder.buildTerm(parts.get(1));
			setof.setGoal(goal);
			Term term=TermBuilder.buildTerm(parts.get(2));
			setof.setTerm(term);
			Variable VarSet=(Variable) TermBuilder.buildTerm(parts.get(3));
			setof.setVarSet(VarSet);
			
			return setof;
		}
		return null;
	}

	public static Executable buildBind(LispObject lo) {
		String varname=((Symbol)lo.cadr()).getName();
		Variable var=new Variable(varname);
		Term temp=TermBuilder.buildTerm(lo.caddr());
		Func func=(Func)temp;
		Bind bind=new Bind(var,func);		
		return bind;
	}
	public abstract List<st>  exec(st state);

	public static Executable buildDebug(LispObject lo) {
		return new Debug();
	}

	public static Executable buildReDebug(LispObject lo) {
		return new ReDebug();
	}
	public String toString(){
		StringBuffer resultb=new StringBuffer();
		resultb.append(this.getClass().getSimpleName());
		resultb.append("( ");
		
		resultb.append(")");
		return resultb.toString();
	}
	
	
}
